home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Sapphire Collection
/
Software Vault (Sapphire Collection) (Digital Impact).ISO
/
cdr47
/
trace122.zip
/
TRACE1.ASM
< prev
next >
Wrap
Assembly Source File
|
1997-02-13
|
43KB
|
1,336 lines
page 60,132
.lfcond
title "TRACE - Interrupt Tracer"
subttl Introduction
page
comment \
TRACE is an INT tracer. It traps INT's, traces the registers at the entry
to the INT, executes the INT itself, and then traces the regs at exit from
the INT. It also allows the user at the keyboard to see all of this traced
information, either at the screen or on the printer.
The INT's that are to be traced are specified in the source code (see config
section below). Once defined, they may be enabled or disabled from the
keyboard.
<<< REBOOT AS SOON AS POSSIBLE AFTER INVOKING TRACE!!! >>>
This is not foolproof or bugfree. We use it 'cause it's a terrific tool
for deprotecting copy-protected software. You use it at your own risk.
When you've gotten a printout of the trace activity that interests you,
reboot your system. Don't say that we didn't warn you.
Enjoy.
Usage is: TRACE [size]
where: size is the size of the trace table in K
between 10 and 63, default is 30
Known problems:
Programs that use: INT 21h function E0
INT 2Eh
\
page
code segment para public 'code'
assume cs:code,ds:code
public trace_begin,trace_curr,trace_end,trace_bytes
public ict_index,hndlr_index,prt_base
public our_cs,test_cs,periscope
public rec_sizes,interp,old_int_5,prtsc
extrn selvideo:near,selprint:near,print:near,print_hex:near
extrn print_word:near,print_wordb:near,crlf:near,print_line:near
extrn table_print:near
extrn print_edit:near,feed:near,key:near,zap_hits:near
extrn prt_sc:near
extrn do_traces:near,do_enable:near,disp_active:near,do_fcb:near
extrn init:near
extrn trace_table:byte
org 0100h
start: jmp init
include b:trace1e.aic
; note that the number of ict's is set by number_icts in trace1e.aic
; and implicetly in code throughout this module.
; note that you need an ICT for some INT 21h AH = 0F0h for the
; detection of TRACE already being installed feature to work
; ICT with low ah = 0dh and high ah = ffh works fine.
; ict parms are:
; flags,flags2,int,low ah, high ah, saved cs:ip,
; count of entries,ict number
; ict flags are:
; f_active tracing on at start-up
; f_ret far ret with original flags, flags on stack
; f_ret2 far ret with updated flags, no flags on stack
; f_iret iret with original flags, no flags on stack
; ict flags2 are:
; f_call This call will return. Example INT 21H, in general
ict0 ICT <F_ACTIVE+F_RET2+F_ENABLE,F_CALL,013H,0,0ffh,0,0,0>
;ROM BIOS INT 13h (all)
ict1 ICT <F_ACTIVE+F_RET+F_ENABLE,0,020h,0,0ffh,0,0,1>
;DOS EXIT
ict2 ICT <F_ACTIVE+F_RET2,F_CALL,021H,0,0ch,0,0,2>
;DOS funcs 00h thru 0Ch
ict3 ICT <F_ACTIVE+F_RET2+F_ENABLE+F_FCB,F_CALL,021H,0dh,030h,0,0,3>
;DOS func 0Dh thru 030h
ict4 ICT <F_ACTIVE+F_RET+F_ENABLE,0,021H,031h,031h,0,0,4>
;DOS func 031h TSR
ict5 ICT <F_ACTIVE+F_RET2+F_ENABLE+F_FCB,F_CALL,021H,032h,04Bh,0,0,5>
;DOS funcs 032h thru 4Bh
ict6 ICT <F_ACTIVE+F_RET2+F_ENABLE,0,021H,04Ch,04Ch,0,0,6>
;DOS func 04Ch EXIT
ict7 ICT <F_ACTIVE+F_RET2+F_ENABLE+F_FCB,F_CALL,021H,04Dh,0ffh,0,0,7>
;DOS funcs 04Dh thru FFh
ict8 ICT <F_ACTIVE+F_RET+F_ENABLE,F_CALL,025h,0,0ffh,0,0,8>
;RAW disk I/O
ict9 ICT <F_ACTIVE+F_RET+F_ENABLE,F_CALL,026h,0,0ffh,0,0,9>
;RAW disk I/O
ict10 ICT <F_ACTIVE+F_RET+F_ENABLE,0,027h,0,0ffh,0,0,10>
;DOS TSR
ict11 ICT <F_ACTIVE+F_RET2+F_ENABLE,0,02Eh,0,0ffh,0,0,11>
;DOS undocumented .BAT call
ict12 ICT <0,0,0,0,0,0,12> ;unused
ict13 ICT <0,0,0,0,0,0,13> ;unused
ict14 ICT <0,0,0,0,0,0,14> ;unused
ict15 ICT <0,0,0,0,0,0,15> ;unused
;*******************************************************
; E N D C O N F I G U R A T I O N
;*******************************************************
subttl Resident Storage
page
;
; Things defined here are present even after we become resident and
; exit to DOS.
;
;********************************************************
;
; Index table pointing to all ICT's
;
;********************************************************
ict_index label word
dw offset ict0
dw offset ict1
dw offset ict2
dw offset ict3
dw offset ict4
dw offset ict5
dw offset ict6
dw offset ict7
dw offset ict8
dw offset ict9
dw offset ict10
dw offset ict11
dw offset ict12
dw offset ict13
dw offset ict14
dw offset ict15
;********************************************************
;
; Index table pointing to all handlers
;
;********************************************************
hndlr_index label word
dw offset handler0
dw offset handler1
dw offset handler2
dw offset handler3
dw offset handler4
dw offset handler5
dw offset handler6
dw offset handler7
dw offset handler8
dw offset handler9
dw offset handler10
dw offset handler11
dw offset handler12
dw offset handler13
dw offset handler14
dw offset handler15
;********************************************************
;
; Trace table pointers. Actual trace table slung over
; initialization code in TRACE12.ASM
;
;********************************************************
trace_begin dw offset trace_table ;address of trace table begin
trace_curr dw offset trace_table ;address of next entry
trace_end dw offset trace_table ;address of end of trace table
trace_bytes dw trace_size ;size of trace table in bytes
;********************************************************
;
; Table of sizes for each trace record type. Must be in same
; order as record types themselves.
;
;********************************************************
rec_sizes label word
dw size BEFORE
dw size AFTER
dw size FCB
dw size ASCIIZ
;********************************************************
;
; Table of INT 21h functions that include an FCB pointer in DS:DX
;
;********************************************************
FCB_table label byte
db 0fh,10h,11h,12h,13h,14h,15h,16h,17h,21h,22h,23h,24h,27h,28h
FCB_end label byte
;********************************************************
;
; Table of INT 21h functions that include an ASCIIZ pointer in DS:DX
;
;********************************************************
ASCIIZ_table label byte
db 4bh,3ch,3dh,41h,43h,4eh,56h,5ah,5bh,39h,3ah,3bh
ASCIIZ_end label byte
;********************************************************
;
; Misc storage
;
;********************************************************
old_int_5 dd ? ;address of previous Prt-Sc routine
our_cs dw 0 ;our CS (not for segment checking)
test_cs dw 0 ;our normalized CS (for segment checking)
long_addr dd 0 ;for long JMP's and CALLs
our_ICT dw 0 ;for quick save of our ICT pointer
our_flags db 0 ;for quick save of our ICT flags
prt_base dw 0 ;base I/O address of printer
;prt_flag db 0 ;non-zero to send output to printer
db 255 dup (0) ;stack for Periscope Int handler
our_tos dw 0 ;top of that stack
stack_inuse db 0 ;non-zero when above stack is in use
save_ss dw 0 ;for stack-swapping
save_sp dw 0
subttl Interrupt Trappers and Tracing
page
;********************************************************
;
; Interrupt handler entry points for each ICT
;
;********************************************************
handler macro ictloc
cli ;*** NO INTERRUPTS!!! ***
push bp ;save stack pointer, so that...
mov bp,sp ;...we can ref things via BP
push bx ;set BX to point to ICT
mov bx,offset cs:ictloc
jmp int_common ;goto common code
endm
interrupt proc far
handler0:
handler ict0
handler1:
handler ict1
handler2:
handler ict2
handler3:
handler ict3
handler4:
handler ict4
handler5:
handler ict5
handler6:
handler ict6
handler7:
handler ict7
handler8:
handler ict8
handler9:
handler ict9
handler10:
handler ict10
handler11:
handler ict11
handler12:
handler ict12
handler13:
handler ict13
handler14:
handler ict14
handler15:
handler ict15
int_common:
push ax
;********************************************************
;
; Common code for all trapped INT's.
;
; At this point:
;
; BX holds ICT address.
; BP points to stack as follows:
;
; AX
; BX
; (BP) ----> BP
; +2 IP of caller
; +4 CS of caller
; +6 FLAGS of caller
;
;********************************************************
; At this point we get the int number in AH. We invent an esoteric INT 21H
; value for telling the initialization code we are already here
cmp cs:[bx].ICT_intnum,21h ;check interrupt # being traced
jne notint21 ;if not 21h go on.
mov ax,-4[bp] ;get original AX
cmp ax,iamhere ;is it me ?
jne notmyint ;no, go on
mov word ptr -2[bp],iamhere ;set BX to flag
notmyint:
pop ax ;restore ah
push ax ;restore stack
notint21:
test cs:[bx].ICT_flags,F_ENABLE ;tracing enabled for this ICT?
jz no_trace ;no, don't trace it
cmp ah,cs:[bx].ICT_AH_lo ;is AH within bounds?
jb no_trace ;no, don't trace it
cmp ah,cs:[bx].ICT_AH_hi
ja no_trace ;no, don't trace it
;
; See if we should check caller's CS:IP
;
test cs:[bx].ICT_flags,F_BELOW+F_ROM
jz int_common3 ;no segment checks to be made
mov ax,2[bp] ;get caller's IP
shr ax,1 ;prepare to normalize segment #
shr ax,1
shr ax,1
shr ax,1
add ax,4[bp] ;add in segment
;
; ------ AX now equals normalized segment #
;
test cs:[bx].ICT_flags,F_BELOW
jz int_common2 ;don't check for invoker below us
cmp ax,cs:test_cs ;is caller below us?
jb no_trace ;yes, don't trace
int_common2:
test cs:[bx].ICT_flags,F_ROM
jz int_common3 ;don't check for invoker in ROM
cmp ax,0c000h ;is caller in ROM?
jae no_trace ;yes, don't trace
int_common3:
;
; See if we have room for this trace
;
mov ax,cs:trace_curr ;get address of next entry
push ax
add ax,size BEFORE ;add size of this record
; cmp ax,offset cs:last_byte ;would record fit?
cmp ax,cs:trace_end ;would record fit?
pop ax
jb yes_trace ;yes, there's room
no_trace:
;
; We are not to trace this INT, for whatever reason.
; Just go to original handler, and return to caller (not to us).
;
mov ax,word ptr cs:[bx].ICT_orig_hndlr
mov word ptr cs:long_addr,ax
mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
mov word ptr cs:long_addr+2,ax
pop ax
pop bx
pop bp
jmp cs:long_addr ;let original handler return to caller
yes_trace:
;
; We are to proceed with trace of this INT. Make trace entry.
;
push es
push di
;
; At this point:
;
; AX holds offset to next trace entry.
; BX holds ICT address.
; BP points to stack as follows:
;
; DI
; ES
; AX
; BX
; (BP) ----> BP
; +2 IP of caller
; +4 CS of caller
; +6 FLAGS of caller
;
mov di,ax ;set ES:DI to next trace entry
mov ax,cs
mov es,ax
cld ;forward!!!
mov ah,cs:[bx].ICT_intnum ;get interrupt # being traced
mov al,cs:[bx].ICT_num ;get ICT #, make BEFORE record type
stosw
mov ax,-4[bp] ;original AX
stosw
mov ax,-2[bp] ;original BX
stosw
mov ax,cx
stosw
mov ax,dx
stosw
mov ax,-6[bp] ;original ES
stosw
mov ax,ds
stosw
mov ax,ss
stosw
mov ax,bp ;original SP
add ax,2
stosw
mov ax,si
stosw
mov ax,-8[bp] ;original DI
stosw
mov ax,[bp] ;original BP
stosw
mov ax,4[bp] ;caller's CS
stosw
mov ax,2[bp] ;caller's IP
stosw
mov cs:trace_curr,di ;save spot for next trace entry
inc cs:[bx].ICT_hits ;bump number of traces made for this ICT
;
; We're done with the BEFORE trace. See if we are to do an FCB or ASCIIZ
; trace record.
;
test cs:[bx].ICT_flags,F_FCB
jz no_FCB ;no, we are definitely not supposed to
cmp cs:[BX].ICT_intnum,021h ;is this an INT 21h?
jnz no_FCB ;no, can't trace it then
;
; Search through ASCIIZ function table, to see if function that was called
; is one that contains an ASCIIZ pointer in DS:DX
;
mov ax,-4[bp] ;get AX at time of call
push cx
mov di,offset cs:ASCIIZ_table
mov cx,offset cs:ASCIIZ_end
sub cx,di ;CX now has size of table
mov al,ah ;get function to AL
repnz scasb ;see if it's in table
pop cx
jz trace_ASCIIZ ;it's there, so do ASCIIZ trace
;
; Search through FCB function table, to see if function that was called
; is one that contains an FCB pointer in DS:DX
;
push cx
mov di,offset cs:FCB_table
mov cx,offset cs:FCB_end
sub cx,di ;CX now has size of table
repnz scasb ;see if it's in table
pop cx
jnz no_FCB ;no FCB or ASCIIZ trace called for
;
; We are to do trace of FCB pointed to by DS:DX
;
mov al,00100000b ;trace record number for FCB trace
mov ah,size FCB ;size of record
jmp short trace_common ;rest is common code
trace_ASCIIZ:
;
; We are to do trace of ASCIIZ string pointed to by DS:DX
;
mov al,00110000b ;trace record number for ASCIIZ trace
mov ah,size ASCIIZ ;size of record
trace_common:
;
; Copy bytes from DS:DX to new ASCIIZ or FCB trace record.
;
; At this point:
;
; AL holds trace record type, properly positioned in bits 7-4
; AH holds size of record that we're doing (the full record)
;
sub ah,2 ;minus two bytes for record header
mov di,cs:trace_curr ;see if there's room...
push di
push ax
mov al,ah ;get record size to AX
xor ah,ah
add di,ax
cmp di,cs:trace_end
pop ax
pop di
jae no_FCB ;no room
push ax ;save AX over this
mov ah,cs:[bx].ICT_intnum ;start header with interrupt #
or al,cs:[bx].ICT_num ;add ICT number to trace type
stosw ;start new record with it
pop ax ;restore AX
push cx
push si
mov si,dx ;access DS:DX as DS:SI
mov cl,ah ;record size to CX
xor ch,ch
rep movsb ;that's how many to copy
pop si
pop cx
mov cs:trace_curr,di ;save offset to next record
no_FCB: ;end of FCB/ASCIIZ tracing
;end of tracing, period
test cs:[bx].ICT_flags2,F_CALL
jnz call_old ;if marked for call then call far
;else: for ints that don't return like 20h and 27h then just jmp far
mov ax,word ptr cs:[bx].ICT_orig_hndlr
mov word ptr cs:long_addr,ax
mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
mov word ptr cs:long_addr+2,ax
pop di
pop es
pop ax
pop bx
pop bp
jmp cs:long_addr ;invoke original handler via jump
call_old:
;
; Having traced all of those, now invoke original interrupt handler. Have
; it return to us, not the original caller of the interrupt.
;
mov cs:our_ICT,bx ;save ICT pointer for a nanosecond
mov al,cs:[bx].ICT_flags ;save copy of flags that we can get to
mov cs:our_flags,al
mov ax,word ptr cs:[bx].ICT_orig_hndlr
mov word ptr cs:long_addr,ax
mov ax,word ptr cs:[bx].ICT_orig_hndlr+2
mov word ptr cs:long_addr+2,ax
pop di
pop es
pop ax
pop bx
pop bp
push cs:our_ICT ;save ICT pointer on stack
test cs:our_flags,F_RET ;should we push flags?
jnz no_flags ;no, cause they'd be left on stack
pushf ;yes, give handler some flags to drop
no_flags:
call cs:long_addr ;invoke original handler
;
; We're back from the real interrupt handler, and can make the "after" trace.
; Our ICT address is on stack.
;
sti ;give world a crack at interrupts
nop
nop
cli ;*** NO INTERRUPTS!!! ***
push bp ;establish stack reference
mov bp,sp
pushf ;save resultant flags
push es
push di
push ax
push bx
;
; At this point:
;
; BX
; AX
; DI
; ES
; FLAGS (as returned by real interrupt)
; (BP) --------> BP
; ICT address
; IP of caller
; CS of caller
; FLAGS of original caller
;
mov bx,2[bp] ;recover ICT address
mov di,cs:trace_curr ;room for "after" trace entry?
push di
add di,size AFTER
; cmp di,offset cs:last_byte
cmp di,cs:trace_end
pop di
jae no_after ;no, skip it
mov ax,cs ;make ES:DI point to next entry
mov es,ax
cld ;forward!!!
mov ah,cs:[bx].ICT_intnum ;get interrupt #
mov al,cs:[bx].ICT_num ;get ICT #, make AFTER record type
or al,00010000b
stosw
mov ax,-8[bp] ;AX at int's return
stosw
mov ax,-10[bp] ;BX at int's return
stosw
mov ax,cx
stosw
mov ax,dx
stosw
mov ax,-4[bp] ;ES at int's return
stosw
mov ax,ds
stosw
mov ax,si
stosw
mov ax,-6[bp] ;DI at int's return
stosw
mov ax,[bp] ;BP at int's return
stosw
mov ax,-2[bp] ;FLAGS at int's return
stosw
mov cs:trace_curr,di ;save offset to next entry
no_after:
;
; All done making "after" trace, or we've skipped it cause there was
; no room for it.
;
; Now just exit back to the original caller.
;
mov al,cs:[bx].ICT_flags ;save flags where we can get to them
mov cs:our_flags,al
pop bx
pop ax
pop di
pop es
popf
pop bp
pop cs:our_ICT ;drop ICT address without affecting flags
;
; HOW we exit is extremely important. We must exit the same way that the
; real interrupt does.
;
pushf ;save current flags in case we return them
test cs:our_flags,F_RET
jnz exit_ret
test cs:our_flags,F_RET2
jnz exit_ret2
;
; Assume IRET.
;
exit_iret:
popf ;exit via IRET, reloading original flags
STI ;Allow interrupts now
iret
exit_ret2:
popf ;exit via RET 2, discarding original flags
STI ;Allow interrupts now
ret 2
exit_ret:
popf ;exit via far RET, leaving original flags
STI ;Allow interrupts now
ret
interrupt endp
page
;*********************************************
;
; Handle main menu selection whose ASCII keypress is in AL.
;
; Returns: CARRY SET if we should loop back to main menu.
; CARRY CLEAR to exit.
;
;*********************************************
do_main proc near
push ax
cmp al,'P' ;select printer?
jnz do_main1 ;no
call selprint ;yes, do it
stc ;"Loop back to main menu" flag
jmp short do_main9
do_main1:
cmp al,'S' ;select screen?
jnz do_main2 ;no
call selvideo ;yes, do it
stc ;"Loop back to main menu" flag
jmp short do_main9
do_main2:
cmp al,'T' ;Dump Traces?
jnz do_main3 ;no
call do_traces ;yes, do it
stc ;"Loop back to main menu" flag
jmp short do_main9
do_main3:
cmp al,'E' ;Enable ICT?
jnz do_main4 ;no
mov al,F_ENABLE ;yes, get bit value to set/clear
do_main3b:
call do_enable ;enable/disable F_ENABLE per AL
stc ;"Loop back to main menu" flag
jmp short do_main9
do_main4:
cmp al,'D' ;Disable ICT?
jnz do_main5 ;no
mov al,0 ;yes, get bit value to set/clear
jmp do_main3b
do_main5:
cmp al,'L' ;List ICT's?
jnz do_main6 ;no
call disp_active ;yes, do it
stc ;"Loop back to main menu" flag
jmp short do_main9
do_main6:
cmp al,'C' ;Clear trace table?
jnz do_main7 ;no
call zap_hits ;yes, do it
stc ;"Loop back to main menu" flag
jmp short do_main9
do_main7:
cmp al,'Q' ;Quit?
jnz do_main7a ;no
clc ;"Exit" flag
jmp short do_main9
do_main7a:
cmp al,'W' ;PrtSc call?
jnz do_main8 ;no
call prt_sc
clc ;"Exit" flag
jmp short do_main9
do_main8:
cmp al,'F' ;F_FCB toggle?
jnz do_main8B ;no
call do_fcb ;yes, toggle something
stc ;"Loop back to main menu" flag
jmp short do_main9
do_main8b:
; ------ Unknown selection
stc ;"Loop back to main menu" flag
do_main9:
pop ax
ret
do_main endp
subttl Interpretation - Misc Routines
page
;********************************************************************
;* *
;* This file contains the routines that interpret selected *
;* BEFORE trace records and print out sensible summaries of *
;* their meanings. This sure beats having to read a lotta hex *
;* function codes. *
;* *
;* The main routine - interp() - is called just after we've *
;* printed all of the trace record in hex. If this record is *
;* one that we know about, we should now print a one-line *
;* interpretation of the record. This is done via lower-level *
;* routines called by interp() per the INT in the record. *
;* *
;********************************************************************
;********************************************************************
;
; Interpret BEFORE trace record at [SI].
;
;********************************************************************
interp proc near
push bx
push ax
mov ah,[SI].B_int ;get INT type
mov bx,offset interp_tab ;point to table of handlers
interp2:
cmp ah,[bx] ;does this handler go with this INT?
jnz interp5 ;no
mov bx,1[bx] ;yes, get handler's address
call bx ;call that handler
jmp interp9 ;exit
interp5:
add bx,3 ;up to next entry in table
cmp bx,offset interp_end ;searched whole table yet?
jb interp2 ;no, try next one
interp9:
pop ax
pop bx
ret
interp endp
;
; Table of interpreters for various interrupts.
;
; Each entry is as follows:
;
; db <intnum> ;interrupt number
; dw offset <handler> ;address of handler to interpret this int's record
;
;
interp_tab label byte
db 013h ;INT 13h is Diskette I/O
dw offset interp_13 ;handler for INT 13h
db 020h ;INT 20h is DOS Program exit
dw offset interp_20 ;handler for INT 20h
db 021h ;INT 21h is DOS Function Handler
dw offset interp_21 ;handler for INT 21h
db 025h ;INT 025H is DOS ABSOLUTE DISK READ
dw offset interp_25
db 026h ;INT 026H is DOS ABSOLUTE DISK WRITE
dw offset interp_25 ;uses same interpreter
db 027h ;INT 027H is DOS TSR
dw offset interp_27 ;uses same interpreter
db 02Eh ;INT 02EH is undoc DOS .BAT
dw offset interp_2E ;uses same interpreter
interp_end label byte ;end of table
subttl Interpretation - INT 13 (Diskette I/O)
page
;
; Tables used to interpret INT 13h in TRACE1E.AIC
;
Floppy_or_Hard db 0,"Floppy:",0
db 080h,"Fixed:",080h
Cyl_or_Track db 0,"Track:",0
db 080h,"Cyl:",080h
int13_line label byte
db cr,lf," "
db Edit_Call
int13_F_or_H db 0
dw offset Floppy_or_Hard
dw offset table_print
db Edit_Dec8
int13_drive db 0
db " Head:"
db Edit_Dec8
int13_head db 0
db " "
db Edit_Call
int13_C_or_T db 0
dw offset Cyl_or_Track
dw offset table_print
db Edit_Dec16
int13_cyl dw 0
db " Sect:"
db Edit_Dec8
int13_sect db 0
db " #Sects:"
db Edit_Dec8
int13_numsects db 0
db " "
db Edit_Call
int13_func db 0
dw offset int13_functab
dw offset table_print
db Edit_End
;**************************************************
;
; Interpret INT 13h BEFORE trace record at [SI]
;
;**************************************************
interp_13 proc near
push dx
push cx
push ax
mov dx,[SI].B_dx ;get DX at time of INT
mov al,dl ;Get drive #
and al,080h ;isolate floppy/hard bit
mov int13_F_or_H,al ;use it to select device name...
mov int13_C_or_T,al ;...as well as cylinders/tracks
and dl,07fh ;isolate drive #
mov int13_drive,dl
mov int13_head,dh ;store head #
mov cx,[SI].B_cx ;get CX at time of INT
xor ax,ax ;calc 10-bit cylinder #
mov al,cl
shl ax,1
shl ax,1
mov al,ch
mov int13_cyl,ax ;save as word
and cl,00111111b ;isolate sector #
mov int13_sect,cl
mov ax,[SI].B_ax ;get AX at time of INT
mov int13_numsects,al
mov int13_func,ah
mov dx,offset int13_line ;now print edited line
call print_edit
pop ax
pop cx
pop dx
ret
interp_13 endp
subttl Interpretation - INT 20h (DOS)
page
int20_line label byte
db cr,lf," DOS: interrupt 20h - terminate program"
db Edit_End
;**************************************************
;
; Interpret INT 20h BEFORE trace record at [SI]
;
;**************************************************
interp_20 proc near
push dx
mov dx,offset int20_line
call print_edit
pop dx
ret
interp_20 endp
subttl Interpretation - INT 21h (DOS)
page
;
; Tables used in interpreting INT 21h
;
include b:trace1.aic
int21_line label byte
db cr,lf," DOS: "
db Edit_Call
int21_func db 0
dw offset int21_functab
dw offset table_print
db Edit_End
;**************************************************
;
; Interpret INT 21h BEFORE trace record at [SI]
;
;**************************************************
interp_21 proc near
push dx
push ax
mov ax,[SI].B_ax ;get AX at time of int
mov byte ptr int21_func,ah ;use it to select function
mov dx,offset int21_line
call print_edit
pop ax
pop dx
ret
interp_21 endp
subttl Interpretation - INT 25h and 26h (Absolute disk I/O)
page
;
; Tables used to interpret INT's 25h and 26h
;
int25_functab label byte
db 025h,"Read",0
db 026h,"Write",080h
int25_line label byte
db cr,lf," DOS Absolute "
db Edit_Call
int25_func db 0
dw offset int25_functab
dw offset table_print
db " Drive:"
db Edit_Dec8
int25_drv db 0
db " Sector:"
db Edit_Dec16
int25_sect dw 0
db " #Sectors:"
db Edit_Dec16
int25_numsects dw 0
db " Buf "
db Edit_Word
int25_seg dw 0
db ":"
db Edit_Word
int25_off dw 0
db Edit_End
;**************************************************
;
; Interpret INT 25h or INT 26h BEFORE trace record at [SI]
;
;**************************************************
interp_25 proc near
push dx
push ax
mov al,[SI].B_int ;get INT that was done (25h or 26h)
mov int25_func,al ;move to printline
mov ax,[SI].B_ax ;get drive # from AL
mov int25_drv,al ;move to printline
mov ax,[SI].B_dx ;get starting sector # from DX
mov int25_sect,ax ;move to printline
mov ax,[SI].B_cx ;get # sectors from CX
mov int25_numsects,ax ;move to printline
mov ax,[SI].B_ds ;get buffer segment from DS
mov int25_seg,ax ;move to printline
mov ax,[SI].B_bx ;get buffer offset from BX
mov int25_off,ax ;move to printline
mov dx,offset int25_line ;now print edited line
call print_edit
pop ax
pop dx
ret
interp_25 endp
int27_line label byte
db cr,lf," DOS: interrupt 27h - TSR"
db Edit_End
;**************************************************
;
; Interpret INT 27h BEFORE trace record at [SI]
;
;**************************************************
interp_27 proc near
push dx
mov dx,offset int27_line
call print_edit
pop dx
ret
interp_27 endp
int2E_line label byte
db cr,lf," DOS: interrupt 2Eh - Undocumented .BAT service"
db Edit_End
;**************************************************
;
; Interpret INT 2Eh BEFORE trace record at [SI]
;
;**************************************************
interp_2E proc near
push dx
mov dx,offset int2E_line
call print_edit
pop dx
ret
interp_2E endp
subttl Periscope Interrupt Interface
page
;*****************************************
;
; This is the interrupt handler use by Periscope to access this code.
; It may also be called by SHIFT-PrtSc.
;
; On entry, AH contains function:
;
; 1 - 8: User Breakpoint checks (BU 1 thru BU 8, then GT)
; 9 - FFh: User exits (/U 9 thru /U FFh)
; 0FFh: Called by PrtSc
;
;*****************************************
db "PS" ;sentinel that Periscope checks for
periscope proc far
;
; First, make very sure that we aren't being re-entered!!! This would
; wipe out our stack which is already in use.
;
cli
test cs:stack_inuse,0ffh
jz periscope2 ;it's ok
periscope1:
mov al,0ffh ;tell Periscope "No Break, No Command to be executed"
iret ;busy, call back later
periscope2:
;
; If we've been entered via Periscope User Break function (during single-stepping,
; with BU 1 thru BU 8 in effect), then exit immediately. Things are slow
; enough without us being executed when we have no Breakpoint checking to do.
;
cmp ah,9 ;BU 1 thru BU 8?
jb periscope1 ;yes, exit
;
; On entry to this periscope int, we ought to save everything but AX,
; and switch to our own stack. Periscope itself doesn't require this,
; but the PrtSc routine assumes it.
;
mov cs:stack_inuse,0ffh ;mark our stack busy
mov cs:save_ss,ss
mov cs:save_sp,sp
mov ss,cs:our_cs
mov sp,offset our_tos
push cs:save_ss ;save old stack stuff for later
push cs:save_sp
push bx
push cx
push dx
push si
push di
push es
push ds
push bp
mov ds,cs:our_cs ;set DS to us for assume ds:code
sti
;
; Give user stats about trace buffer size
;
mov ax,trace_bytes
mov word ptr size_trace,ax
; mov ax,offset last_byte ;get # free bytes
mov ax,trace_end ;get # free bytes
sub ax,trace_curr
mov word ptr size_freeb,ax
mov dx,offset size_msg
call print_edit
periscope_menu:
;
; Now display menu and get his selection, until we are to exit
;
mov dx,offset mainmenu
call print_line ;put up main menu
call feed ;extra CRLF's for printer
call key ;get keypress
call do_main ;process it
jc periscope_menu ;we are to loop back
mov dx,offset shadows ;give him exit message
call print_line
periscope_exit:
;
; Restore regs and original stack. AX is already set to return result.
;
cli
pop bp
pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop cs:save_sp ;restore original stack
pop cs:save_ss
mov ss,cs:save_ss
mov sp,cs:save_sp
mov cs:stack_inuse,0 ;mark our stack not busy
iret
periscope endp
mainmenu db cr,lf
db " TRACE Commands:",cr,lf
db " Output to: Trace Trace Sel List ICT "
db " Trace Cmd PrtSc",cr,lf
db "(P)rt (S)crn (E)nable (D)isable (F)CB (T)race (L)ist "
db "(C)lear (Q)uit (W)rite",cr,lf,"$"
shadows db cr,lf
db "Back to DOS"
db cr,lf,"$"
size_msg label byte
db cr,lf
db "TraceBuf Bytes:"
db Edit_Dec16
size_trace dw 0
db " Free Bytes:"
db Edit_Dec16
size_freeb dw 0
db Edit_End
subttl INT 05 (SHIFT-PrtSc) Handler
page
;**************************************************
;
; This is another way (besides Periscope) to talk to the tracer, and
; get it to report what it's found. This is not as clean a way as
; via Periscope, but it beats nothing if the Periscope board isn't in
; the system.
;
; This routine just calls the Periscope interrupt handler.
;
;**************************************************
if prt_scr
PrtSc proc far
cli
push es
push ax
mov ax,050h ;set ES to 0050:0000
mov es,ax ;(the print-screen control byte)
cmp byte ptr es:[0],1 ;are we busy with previous request?
jz PrtSc_exit ;yes, don't do anything
mov byte ptr es:[0],1 ;no, mark us busy now
mov ah,0ffh ;call Periscope INT with special arg
int peri_int
mov byte ptr es:[0],0 ;mark us not busy now
PrtSc_exit:
pop ax
pop es
iret
Prtsc endp
endif
code ends
end start